package wml.clipstore.storage.clips;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;

import test.beans.User;
import wml.clipstore.base.Entity;
import wml.clipstore.map.MapManager;
import wml.clipstore.utils.EntityUtils;
import CLIPSJNI.Environment;

class ClipsSaver {

	private Environment clips;

	public static void main(String[] args) {
		User u = new User();
		System.out.println((u instanceof Entity));
	}

	ClipsSaver(Environment clips) {
		this.clips = clips;
	}

	public void save(Entity entity) {
		List<String> instances = this.toInstances(entity);
		this.definstances(instances);
	}

	private void definstances(List<String> instances) {
		for (String instance : instances) {
			StringBuilder mins = new StringBuilder("(make-instance ").append(
					instance).append(")");
			clips.eval(mins.toString());
		}
		clips.run();
	}

	private List<String> toInstances(Entity entity) {
		Set<Integer> entities = new HashSet<Integer>();
		List<String> instances = new ArrayList<String>();
		Stack<Object> toIntprt = new Stack<Object>();
		toIntprt.add(entity);
		while (!toIntprt.isEmpty()) {
			Object o = toIntprt.pop();
			if (entities.contains(o.hashCode()))
				continue;
			entities.add(o.hashCode());
			if (o instanceof Entity) {
				instances.add(interpret((Entity) o, toIntprt));
			} else if (o instanceof Collection) {
				instances.add(interpret((Collection<?>) o, toIntprt));
			}
		}
		return instances;
	}

	private String interpret(Entity entity, Stack<Object> toIntprt) {
		String className = entity.getClass().getName();
		StringBuilder ins = new StringBuilder(className).append(".")
				.append(entity.hashCode()).append(" of ").append(className)
				.append(" (class ").append(className).append(")");
		List<Field> fields = MapManager.getInstance().getStoredFields(entity.getClass());
		for (Field f : fields) {
			Object value = EntityUtils.getValue(entity, f);
			if (value instanceof Entity || value instanceof Collection) {
				ins.append("(f_").append(f.getName()).append(" [")
						.append(value.getClass().getName()).append(".")
						.append(value.hashCode()).append("])");
				toIntprt.add(value);
			} else {
				String vClassName = (value == null) ? "null" : value.getClass()
						.getName();
				ins.append("(f_").append(f.getName()).append(" \"")
						.append(value).append("@").append(vClassName)
						.append("\"").append(")");
			}
		}
		return (ins.toString());
	}

	private String interpret(Collection<?> entity, Stack<Object> toIntprt) {
		String className = entity.getClass().getName();
		StringBuilder instance = new StringBuilder(className).append(".")
				.append(entity.hashCode())
				.append(" of java.util.Collection (class ").append(className)
				.append(") (items ");
		for (Object value : entity) {
			String vClassName = (value == null) ? "null" : value.getClass()
					.getName();
			if (value instanceof Entity || value instanceof Collection) {
				instance.append(" [").append(vClassName).append(".")
						.append(value.hashCode()).append("]");
				toIntprt.add(value);
			} else {
				instance.append(" \"").append(value).append("@")
						.append(vClassName).append("\"");
				instance.append(" ").append(value);
			}
		}
		return instance.append(")").toString();
	}
}
